#include <iostream>
#include <unistd.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <vector>
#include <ctime>
#include "Task.hpp"
#define PROCESS_NUM 5
using namespace std;
int read_command(int waitfd,bool * b)
{
    uint32_t command = 0;
    ssize_t s = read(waitfd,&command,sizeof command);//如果别人没发 那就一直阻塞等待
    if(s == 0)
    {
        *b = 1;
        return -1;
    }
    assert(s==sizeof (uint32_t));
    (void)s;
    return command;
}

void SendAndWakeUp(int sendfd,uint32_t command,pid_t id)
{
    write(sendfd,&command,sizeof(command));
    cout<<"父进程派发"<<"pid:"<<id<<"成功"<<endl;
}

int main()
{
	int count = 10;
	srand((unsigned int)time(nullptr));
    load();
    std::vector<std::pair<pid_t,int>> slots;
    //1创建相应数量的子进程
    for(int i = 0;i < PROCESS_NUM;i++)
    {
        int process_fd[2] = {0};
        int n = pipe(process_fd);
        assert(n>=0);
        (void)n;
        int id = fork();
        assert(id != -1);
        if(id == 0)//这里是子进程
        {
            close(process_fd[1]);//子进程先关闭写端
            while(1)
            {
                bool boolnum = 0;
                int command = read_command(process_fd[0],&boolnum);
                if(boolnum == 1)
                {
                    cout<<"我读到文件结尾了，我要break了"<<endl;
                    break;
                }
                if(command>=0 && command<=callbacks.size())
                {
                    callbacks[command]();
                }
                else
                {
                    cout<<"输入非法\n"<<endl;
                }
            }
            exit(1);
        }
        //这里是父进程
        close(process_fd[0]);//父进程先关闭读端
        slots.push_back(pair<pid_t,int>(id,process_fd[1]));//父进程构建子进程pid与对应写端的键值对表
    }
    for(auto e:slots)
    {
        cout<<e.first<<' '<<e.second<<endl;
    }
    while(count--)//rand()%10
    {
        uint32_t command = 0;
        int choice1 = (rand()%PROCESS_NUM * getpid() * 31)%PROCESS_NUM;
        uint32_t choice2 = (rand()%callbacks.size() * getpid() * 31)%callbacks.size();
        //父进程派发任务
        cout<<choice1<<' '<<choice2<<endl;
        SendAndWakeUp(slots[choice1].second,choice2,slots[choice1].first);//需要的参数有要给哪个子进程派任务，要给子进程派哪个任务
        sleep(1);
    }
    for(auto &iter:slots)
    {
        close(iter.second);
        cout<<"fd关闭成功"<<endl;
    }

    for(auto &iter:slots)
    {
        waitpid(iter.first,nullptr,0);
        cout<<"清理僵尸进程成功"<<endl;
    }
    return 0;
}
